#include <sys/time.h>   
#include <stdio.h>   
#include <math.h>
#include <string.h>
#include <cutil.h>
#include <cuda.h>
#include <getopt.h>
#include <stdlib.h>

#include "svmCommon.h"
#include "../common/svmIO.h"
#include "../common/framework.h"
#include "kernelType.h"


void performTraining(float* data, int nPoints, int nDimension, float* labels, float** p_alpha, Kernel_params* kp, float cost, SelectionHeuristic heuristicMethod, float epsilon, float tolerance, float* transposedData);



static int kType = GAUSSIAN;

int main( const int argc, const char** argv)  { 
  int currentOption;
  
  SelectionHeuristic heuristicMethod = ADAPTIVE;
  float cost = 10.0f;
  
  float tolerance = 1e-3f;
  float epsilon = 1e-5f;
  char* outputFilename = NULL;
  while (1) {
    
    int optionIndex = 0;
    currentOption = getopt_long(argc, (char *const*)argv, "c:h:t:e:o:a:r:d:g:v:f", longOptions, &optionIndex);
    if (currentOption == -1) {
      break;
    }
    int method = 3;
    switch (currentOption) {
    case 0:
      break;
    case 'v':
      printf("GPUSVM version %1.1f\n", VERSION);
      return(0);
    case 'f':
      printHelp();
      return(0);
    case 'c':
      sscanf(optarg, "%f", &cost);
      break;
    case 'h':
      sscanf(optarg, "%i", &method);
      switch (method) {
      case 0:
        heuristicMethod = FIRSTORDER;
        break;
      case 1:
        heuristicMethod = SECONDORDER;
        break;
      case 2:
        heuristicMethod = RANDOM;
        break;
      case 3:
        heuristicMethod = ADAPTIVE;
        break;
      }
      break;
    case 't':
      sscanf(optarg, "%f", &tolerance);
      break;
    case 'e':
      sscanf(optarg, "%e", &epsilon);
      break;
    case 'o':
      outputFilename = (char*)malloc(strlen(optarg));
      strcpy(outputFilename, optarg);
      break;
    case 'a':
      sscanf(optarg, "%f", &parameterA);
      parameterASet = true;
      break;
    case 'r':
      sscanf(optarg, "%f", &parameterB);
      parameterBSet = true;
      break;
    case 'd':
      sscanf(optarg, "%f", &parameterC);
      parameterCSet = true;
      break;
    case 'g':
      sscanf(optarg, "%f", &parameterA);
      parameterA = -parameterA;
      parameterASet = true;
      break;
    case '?':
      break;
    default:
      abort();
      break;
    }
  }

  if (optind != argc - 1) {
    printHelp();
    return(0);
	}

  const char* trainingFilename = argv[optind];
  
  if (outputFilename == NULL) {
    int inputNameLength = strlen(trainingFilename);
    outputFilename = (char*)malloc(sizeof(char)*(inputNameLength + 5));
    strncpy(outputFilename, trainingFilename, inputNameLength + 4);
    char* period = strrchr(outputFilename, '.');
    if (period == NULL) {
      period = outputFilename + inputNameLength;
    }
    strncpy(period, ".mdl\0", 5);
  }
  
	
	int nPoints;
	int nDimension;
	float* data;
	float* transposedData;
	float* labels;
	readSvm(trainingFilename, &data, &labels, &nPoints, &nDimension, &transposedData);
	printf("Input data found: %d points, %d dimension\n", nPoints, nDimension);
  
	float* alpha;
  
    

	struct timeval start;
	gettimeofday(&start, 0);
	performTraining(data, nPoints, nDimension, labels, &alpha, &kp, cost, heuristicMethod, epsilon, tolerance, transposedData);

	struct timeval finish;
	gettimeofday(&finish, 0);
	float trainingTime = (float)(finish.tv_sec - start.tv_sec) + ((float)(finish.tv_usec - start.tv_usec)) * 1e-6;
	
	printf("Training time : %f seconds\n", trainingTime);
	printModel(outputFilename, kp, alpha, labels, data, nPoints, nDimension, epsilon);
	
}

